<?php
/*******************
 # 写日志-基类
 # 强烈建议：
 # 1.既然是日志，就要写到文件里，节省数据库开销
 # 2.如果要想灵活查询日志，可以定时分批将日志信息整理分拣入库，以备查询
 # 3.日志内会有敏感信息，请控制日志目录权限
 # lsj 2009-12-27
******************/

if(!defined('APP_HOME')) exit('Access Denied');

class lib_Log
{
	protected static $logFP = array();#记录读取一个日志文件的HANDLE
	protected $logFile = null;#日志文件的路径
	protected $ctrl = null;#当前控制器
	protected $logMonth = 0;#日志信息记录保留时间（月），默认三个月，为０时不自动清除


	public function __construct($ctrl)
	{
		$this->ctrl = $ctrl;
		$this->clear();
		$this->init();
	}

	public function __destruct()
	{
		self::$logFP = array();
	}

	/**
	 * 实例化时的最后一个工作
	 */
	public function _init()
	{

	}

	/**
	 * 设置日志保留期限
	 * $n为0时就会不自动清除，长期保存
	 */
	public function setTerm($n) 
	{
		$this->logMonth = intval($n) % 12;#不能超过１２个月，不能小于一个月
		return $this;
	}

	/**
	 * 清除过期日志
	 * 保证每个控制器的操作目录下始终有最近的规定期限的日志文件
	 */
	public function clear() 
	{
		if($this->logMonth <= 0) return false;

		$y = date('Y');
		$m = date('m');
		$n = $m - $this->logMonth;

		if($n <= 0) $logTerm = ($y - 1) . (12 + $n);
		else $logTerm = $y . $n;

		$path = LOG_ROOT;
		$path .= $this->ctrl->getCtrlName() . DS;
		$path .= $this->ctrl->getActionName() . DS;
		$path .= $logTerm;

		if(is_dir($path)){
			if($d = opendir($path)){
				while(false !== ($file = readdir($d))){
					if($file == '.' || $file == '..') continue;
					if(intval($file) <= $logTerm){
						@unlink($path.DS.$file);
					}
				}
			}
		}

		return true;
	}

	
	/**
	 * 将重要信息以及序列化后的$_GET,$_POST,$_COOKIE,$_FILES客户端信息，写入文件
	 * 返回数组形式日志信息
	 * $info：要记录的重要信息，一般为登录的用户信息。可为空
	 */
	public function write($info = '')
	{
		$log = date('Y-m-d H:i:s');
		$log .= ' ' . $this->ctrl->getCtrlName();
		$log .= ' ' . $this->ctrl->getActionName();
		if($info) $log .= ' ' . $info;
		$log .= ' GET=' . serialize($_GET);
		$log .= ' POST=' . serialize($_POST);
		$log .= ' COOKIE=' . serialize($_COOKIE);
		$log .= ' FILES=' . serialize($_FILES);
		$log .= "\r\n";

		$this->getLogFile();
		makeDir(dirname($this->logFile));
		if(!file_exists($this->logFile)) $log = "<?php if(!defined('APP_HOME')) exit('Access Denied');?>\r\n".$log;
		if($fp = fopen($this->logFile, 'a')){
			flock($fp, LOCK_EX);
			fwrite($fp, $log);
			flock($fp, LOCK_UN);
			return $log;
		}
		
		return false;
	}
	
	/**
	 * 一行一行地读取日志信息
	 * 返回值：false:读取失败   null:读取完毕   正常返回字符串
	 */
	public function read($ctl, $act, $date)
	{
		$this->getLogFile($date, $ctl, $act);
		if(!file_exists($this->logFile)) return false;
		$L = str_replace(DS, '_', $this->logFile);

		if(!isset(self::$logFP[$L])){
			self::$logFP[$L] = @fopen($this->logFile, 'r');
		}

		if(!isset(self::$logFP[$L])){
			if(!feof(self::$logFP[$L])) return fgets(self::$logFP[$L], 10240);
			else return null;
		}

		return false;
	}

	/**
	 * 搜索日志信息，LINUX系统下可用。调用外部命令实现
	 * 返回所在行的信息，那么关键字信息就应该是明文的
	 * $key: 搜索关键字
	 */
	public function find($key, $ctl = '', $act = '', $date = '')
	{
		if(strpos(strtolower(PHP_OS), 'unix') === false) return null;
		$path = LOG_ROOT;
		$file = '*.log.php';
		if($ctl){
			$path .= $ctl;
			if($act) $path .= $act;
			if($date){
				$this->getLogFile();
				$path = dirname($this->logFile);
				$file = basename($this->logFile);
			}
		}
		
		$shell = 'find '.$path.' -name '.$file.' -exec grep -l {} \;';
		exec($shell, $return, $flag);
		if($flag == 2) return $return;

		return null;
	}

	/**
	 * 获取日志文件名
	 * 日志目录：按‘月-控制器-方法’来分
	 * 日志文件：按天来分
	 */
	public function getLogFile($date = '', $ctl = '', $act = '')
	{
		if(!$date) $date = time();
		elseif(is_string($date)) $date = strtotime();
		if(!$ctl) $ctl = $this->ctrl->getCtrlName();
		if(!$act) $act = $this->ctrl->getActionName();

		$this->logFile = LOG_ROOT . $ctl . DS . $act . DS;
		$this->logFile .= date('Ym', $date) . DS . date('d', $date) . '.log.php';
		
		return $this->logFile;
	}






}



